package com.bus.core.configs;

import com.bus.core.BusChannelClient;
import com.bus.core.PubEndpoint;
import com.bus.core.channels.OrderBusChannelClient;
import com.bus.core.channels.ProductBusChannelClient;
import com.bus.core.events.RemoteBusEvent;
import com.bus.core.events.order.OrderRemoteEvent;
import com.bus.core.events.product.ProductRemoteEvent;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.stream.annotation.EnableBinding;
import org.springframework.cloud.stream.annotation.StreamListener;
import org.springframework.cloud.stream.config.BindingProperties;
import org.springframework.cloud.stream.config.BindingServiceProperties;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.EventListener;
import org.springframework.core.env.Environment;
import org.springframework.integration.support.MessageBuilder;
import org.springframework.messaging.MessageChannel;

import javax.annotation.PostConstruct;

import static com.bus.core.channels.OrderBusChannelClient.INPUT_ORDER;
import static com.bus.core.channels.ProductBusChannelClient.INPUT_PRODUCT;

@Configuration
@EnableBinding({OrderBusChannelClient.class,ProductBusChannelClient.class})
@Slf4j
public class BusAutoConfiguration implements ApplicationEventPublisherAware {

    @Autowired
    ApplicationContext applicationContext;

    @Autowired
    Environment environment;

    private ApplicationEventPublisher applicationEventPublisher;

    @Value("${zhan.app.id}")
    private  String appId;

    @Bean
    public PubEndpoint  pubEndpoint(){
        return new PubEndpoint(applicationEventPublisher ,appId);
    }


    @EventListener(classes = RemoteBusEvent.class)
    public void acceptLocal(RemoteBusEvent event) {

        if (!event.getOriginService().equals(appId)){

            return;
        }
        // TODO: 2018/5/28 0028  消息事件和channel的自动化匹配机制 

        if (event instanceof ProductRemoteEvent){
            log.info("监听springcontext 本地事件 ： "+event.getOriginService()+"来自于 "+appId +"是产品事件");
            MessageChannel   outputProduct=  applicationContext.getBean("outputProduct" ,MessageChannel.class);
            outputProduct.send(MessageBuilder.withPayload(event).build());
        }else if (event instanceof OrderRemoteEvent){
            log.info("监听springcontext 本地事件 ： "+event.getOriginService()+"来自于 "+appId+"订单事件");
            MessageChannel   outputOrder=  applicationContext.getBean("outputOrder" ,MessageChannel.class);
            outputOrder.send(MessageBuilder.withPayload(event).build());
        }
        // TODO: 2018/5/26  监听context中的事件 ，如果来自于应用自己，就发布事件到mq中
    }


    // TODO: 2018/5/28 0028  streamListerner 生成的自动生成方式 优化，可以根据 channel和topic自动生成 

    @StreamListener(value = INPUT_ORDER)
    public void inputOrder(RemoteBusEvent event) {
        log.info("收到RemoteBusEvent =====appId ==="+appId+"监听的是 ===="+INPUT_ORDER);

        if (event.getOriginService()!=null&&
                !event.getOriginService().equals(appId)) {
          if (event instanceof  OrderRemoteEvent){
              log.info("收到RemoteBusEvent 是 OrderRemoteEvent");
              this.applicationEventPublisher.publishEvent((OrderRemoteEvent)event);
          }

        }
    }

    @StreamListener(value = INPUT_PRODUCT)
    public void inputProduct(RemoteBusEvent event) {
        log.info("收到RemoteBusEvent ================= appId ==="+appId+"监听的是 ===="+INPUT_PRODUCT);

        if (event.getOriginService()!=null&&
                !event.getOriginService().equals(appId)) {
            if (event instanceof  ProductRemoteEvent){
                log.info("收到RemoteBusEvent 是 ProductRemoteEvent");
                this.applicationEventPublisher.publishEvent((ProductRemoteEvent)event);
            }
        }
    }


    @Autowired
    private BindingServiceProperties bindings;


    @PostConstruct
    public void init() {

        // TODO: 2018/5/28 0028  修改 channel  topic 映射关系生存 
        BusChannelClient.channelList.add(OrderBusChannelClient.INPUT_2_OUTPUT_BEAN);
        BusChannelClient.channelList.add(ProductBusChannelClient.INPUT_2_OUTPUT_BEAN);



        BindingProperties inputBinding = this.bindings.getBindings()
                .get(INPUT_ORDER);
        if (inputBinding == null) {
            this.bindings.getBindings().put(INPUT_ORDER,
                    new BindingProperties());
        }
        BindingProperties input = this.bindings.getBindings()
                .get(INPUT_ORDER);
        if (input.getDestination() == null) {
            input.setDestination(OrderBusChannelClient.TOPIC);
        }
        BindingProperties outputBinding = this.bindings.getBindings()
                .get(OrderBusChannelClient.OUTPUT_ORDER);
        if (outputBinding == null) {
            this.bindings.getBindings().put(OrderBusChannelClient.OUTPUT_ORDER,
                    new BindingProperties());
        }
        BindingProperties output = this.bindings.getBindings()
                .get(OrderBusChannelClient.OUTPUT_ORDER);
        if (output.getDestination() == null) {
            output.setDestination(OrderBusChannelClient.TOPIC);
        }

        /**********/

        BindingProperties inputBinding2 = this.bindings.getBindings()
                .get(INPUT_PRODUCT);
        if (inputBinding2 == null) {
            this.bindings.getBindings().put(INPUT_PRODUCT,
                    new BindingProperties());
        }
        BindingProperties input2 = this.bindings.getBindings()
                .get(INPUT_PRODUCT);
        if (input2.getDestination() == null) {
            input2.setDestination(ProductBusChannelClient.TOPIC);
        }
        BindingProperties outputBinding2 = this.bindings.getBindings()
                .get(ProductBusChannelClient.OUTPUT_PRODUCT);
        if (outputBinding2 == null) {
            this.bindings.getBindings().put(ProductBusChannelClient.OUTPUT_PRODUCT,
                    new BindingProperties());
        }
        BindingProperties output2 = this.bindings.getBindings()
                .get(ProductBusChannelClient.OUTPUT_PRODUCT);
        if (output2.getDestination() == null) {
            output2.setDestination(ProductBusChannelClient.TOPIC);
        }
    }




    @Override
    public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
        this.applicationEventPublisher=applicationEventPublisher;
    }


}
